package com.quick.druid.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.fastjson.JSONObject;
import com.quick.druid.entity.NodeStat;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.*;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: lishuangqiang
 * @Date: 2020/4/29
 * @Description:
 */

@Component
public class DataBaseInfo {
    //固定的根目录比如公司名
    final String fixedpath = "/database5";
    @Autowired
    private Environment env;
    //本地缓存服务列表
    private static Map<String, NodeStat> servermap = new HashMap<>();

    @Bean
    public DataSource getDataSource() throws Exception {
        NodeStat node = servermap.get("nodeStat");
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(node.getUrl());
        dataSource.setUsername(node.getUserName());
        dataSource.setPassword(node.getPassword());
        return dataSource;
    }

    @PostConstruct
    public void init() throws Exception {
//        register();
//        getNodeList();
//        watch();
        watch2();
    }

    private static CuratorFramework getcConnection() {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(100, 3);
        CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", 10000,
                10000, retryPolicy);
        client.start();
        return client;
    }

    private void register() throws Exception {
        NodeStat nodeStat = new NodeStat();
        nodeStat.setUrl(env.getProperty("spring.datasource.url"));
        nodeStat.setUserName(env.getProperty("spring.datasource.username"));
        nodeStat.setPassword(env.getProperty("spring.datasource.password"));
        //临时节点的前缀是服务名称,节点数据是服务address
        String svipmlNode = fixedpath;
        String stat = getcConnection().create().forPath(svipmlNode, JSONObject.toJSONString(nodeStat).getBytes());
        //重点在于这里创建的是临时有序节点
        System.out.println("-----------" + stat);
    }

    private Map getNodeList() throws Exception {
        if (servermap == null) {
            servermap = new HashMap<>();
        }
        byte[] bytes = getcConnection().getData().forPath(fixedpath);
        String s1 = bytesToString(bytes);
        NodeStat nodeStat = JSONObject.parseObject(s1, NodeStat.class);
        servermap.put("nodeStat", nodeStat);
        return servermap;
    }

    public void watch() throws Exception {
        //事件监听
        NodeStat nodeStat = new NodeStat();
        nodeStat.setUrl(env.getProperty("spring.datasource.url"));
        nodeStat.setUserName(env.getProperty("spring.datasource.username"));
        nodeStat.setPassword(env.getProperty("spring.datasource.password"));
        String path = getcConnection().create().forPath(fixedpath, JSONObject.toJSONString(nodeStat).getBytes());
        servermap.put("nodeStat", nodeStat);
        NodeCache nodeCache = new NodeCache(getcConnection(), path, false);
        nodeCache.start(true);
        nodeCache.getListenable().addListener(new NodeCacheListener() {
            @Override
            public void nodeChanged() throws Exception {
                NodeStat node = (NodeStat) servermap.get("nodeStat");
                DruidDataSource dataSource = new DruidDataSource();
                dataSource.setUrl(node.getUrl());
                dataSource.setUsername(node.getUserName());
                dataSource.setPassword(node.getPassword());
                //当节点发生变化的时候这个方法就会被调用
            }
        });
    }

    public   void  watch2() throws Exception {
        //事件监听
        NodeStat nodeStat = new NodeStat();
        nodeStat.setUrl(env.getProperty("spring.datasource.url"));
        nodeStat.setUserName(env.getProperty("spring.datasource.username"));
        nodeStat.setPassword(env.getProperty("spring.datasource.password"));
        String path = getcConnection().create().forPath(fixedpath, JSONObject.toJSONString(nodeStat).getBytes());
        servermap.put("nodeStat", nodeStat);

        PathChildrenCache pathChildrenCache = new PathChildrenCache(getcConnection(), path, false);
        pathChildrenCache.start(true);
        pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
            @Override
            public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
                switch (event.getType()) {
                    case CHILD_ADDED:
                        //当被添加的时候
                        break;
                    case CHILD_UPDATED:
                        //被修改的时候
                        servermap.remove("nodeStat");
                        break;
                    case CHILD_REMOVED:
                        //被移除的时候
                        servermap.remove("nodeStat");
                        break;
                }
            }
        });
    }


    public static String bytesToString(byte[] bs) {
        try {
            // 通过指定的字符集解码指定的byte数组并构造一个新的字符串
            return new String(bs, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }
}
